﻿#include "SemiInfiniteFluidConnectDialog.h"
#include "ui_SemiInfiniteFluidConnectDialog.h"

#include "FITK_Kernel/FITKCore/FITKActionOperator.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKCore/FITKVec3DAlg.h"

#include "FITK_Component/FITKAcousticsModel/FITKAcousticsGroupData.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysSemiInfiniteFluid.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEAFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsTriangles.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysAbsShell.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
// Pick
#include "PickDataProvider/GUIPickInfo.h"
#include "PickDataProvider/PickedDataProvider.h"

#include <QMessageBox>

namespace GUI {

    SemiInfiniteFluidConnectDialog::SemiInfiniteFluidConnectDialog(Core::FITKActionOperator* oper, QWidget* parent /*= nullptr*/) :
        GUIDialogBase(parent),
        _oper(oper),
        _ui(new Ui::SemiInfiniteFluidConnectDialog)
    {
        _ui->setupUi(this);
        // 设置对话框关闭时自动删除
        setAttribute(Qt::WA_DeleteOnClose);
        //去掉问号
        Qt::WindowFlags flags = windowFlags();
        flags &= ~Qt::WindowContextHelpButtonHint;
        setWindowFlags(flags);
        //初始化界面
        this->init();
        //获取拾取器，绑定拾取结束信号
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        //清除拾取对象所有的连接
        QObject::disconnect(pickProvider, SIGNAL(sig_pickedOver()), nullptr, nullptr);
        if (pickProvider)
            connect(pickProvider, &GraphData::PickedDataProvider::sig_pickedOver, this, &SemiInfiniteFluidConnectDialog::pickFinished);
    }

    SemiInfiniteFluidConnectDialog::~SemiInfiniteFluidConnectDialog()
    {
        if (_ui) {
            delete _ui;
            _ui = nullptr;
        }
    }

    void SemiInfiniteFluidConnectDialog::on_pushButton_Cancel_clicked()
    {
        this->reject();
    }

    void SemiInfiniteFluidConnectDialog::on_pushButton_OK_clicked()
    {
        this->pickFinished();
    }

    void SemiInfiniteFluidConnectDialog::on_radioButton_Pick_clicked(bool state)
    {
        if (!state) return;
        //设置下拉框的启用状态
        _ui->comboBox_Group->setEnabled(false);
        //设置拾取模式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJSEASubSystem;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
        //设置拾取方式
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void SemiInfiniteFluidConnectDialog::on_radioButton_Group_clicked(bool state)
    {
        if (!state) return;
        //设置下拉框的启用状态
        _ui->comboBox_Group->setEnabled(true);
        //设置拾取模式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJSEASemiInfFluid;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMSingle;
        //设置拾取方式
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void SemiInfiniteFluidConnectDialog::reject()
    {
        //清除拾取模式和高亮
        GUI::GUIPickInfo::ClearPickInfo();
        this->QDialog::reject();
    }

    void SemiInfiniteFluidConnectDialog::init()
    {
        if (!_oper) return;
        this->initGroupComboBox();

        _ui->radioButton_Pick->setChecked(true);
        this->on_radioButton_Pick_clicked(true);
    }

    void SemiInfiniteFluidConnectDialog::initGroupComboBox()
    {
        Acoustics::FITKAcousticsGroupManager* groupManager = Acoustics::FITKAcousticsGroupManager::GetGroupManagerFromFrame();
        if (!groupManager) return;
        int count = groupManager->getDataCount();
        for (int i = 0; i < count; ++i)
        {
            Acoustics::FITKAcousticsGroupData* data = groupManager->getDataByIndex(i);
            if (!data) continue;
            QString name = data->getDataObjectName();
            _ui->comboBox_Group->addItem(name, data->getDataObjectID());
        }
    }

    void SemiInfiniteFluidConnectDialog::pickFinished()
    {
        if (!_oper) return;
        //获取拾取数据
        GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
        if (provider == nullptr)return;
        disconnect(provider, SIGNAL(sig_pickedOver()), this, SLOT(slotPickJunOverEvent()));
        QList<GraphData::PickedData*> pickList = provider->getPickedList();
        QList<int> idList = {};
        QList<GraphData::PickedFaceData> pickFaceList = {};
        for (GraphData::PickedData* pickData : pickList) {
            if (pickData == nullptr)continue;
            idList.append(pickData->getPickedDataObjId());
            pickFaceList.append(pickData->getPickedSEAFaces());
        }
        if (idList.isEmpty())
        {
            QMessageBox::warning(this, "", tr("Unable to connect! No data is being picked up."), QMessageBox::Ok);
            return;
        }
        //清理拾取模式和高亮
        GUI::GUIPickInfo::ClearPickInfo();
        //获取数据管理器
        if (!_SEAModel || !_DiscModel) return;
        Acoustics::FITKAcousticsSEASubSysManager* subManager = _SEAModel->getSEASubSysManager();
        Acoustics::FITKAcousticsDiscNodeList* nodeList = _DiscModel->getNodes();
        if (nodeList == nullptr || subManager == nullptr)return;
        int semiID = idList[0];
        //判断拾取的第一个是否是半无限流体数据
        Acoustics::FITKSEASubSysSemiInfiniteFluid* semiData = dynamic_cast<Acoustics::FITKSEASubSysSemiInfiniteFluid*>(subManager->getDataByID(semiID));
        if (semiData != nullptr && semiData->getSEASubSysType() != Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEASemiIInfiniteFluid) {
            QMessageBox::warning(this, "", QString(tr("The preference is not a semi-infinite fluid!")), QMessageBox::Ok);
            return;
        }
        //获取半无限流体的位置
        Core::FITKNode* point = nodeList->getNodeByID(semiData->getNodeID());
        if (point == nullptr) return;
        //拾取模式
        if (_ui->radioButton_Pick->isChecked())
        {
            if (idList.size() != 2 || pickFaceList.size() == 0) {
                QMessageBox::warning(this, "", QString(tr("No two subsystems were selected!")), QMessageBox::Ok);
                return;
            }
            //判断拾取的第二个是否是SEA子系统数据
            int subID = idList[1];
            Acoustics::FITKAbstractSEASubSys* subData = subManager->getDataByID(subID);
            if (subData != nullptr) {
                auto type = subData->getSEASubSysType();
                switch (type) {
                case Acoustics::FITKAbstractSEASubSys::SEASSNone:
                case Acoustics::FITKAbstractSEASubSys::SEABeam:
                case Acoustics::FITKAbstractSEASubSys::SEACavity:
                case Acoustics::FITKAbstractSEASubSys::SEASemiIInfiniteFluid: {
                    QMessageBox::warning(this, "", QString(tr("Semi-infinite fluids support only connections to plates!")), QMessageBox::Ok);
                    return;
                }
                }
            }
            //获取连接点
            double connectPoint[3] = { 0,0,0 };
            calculateConnectPoint(pickFaceList[0], connectPoint);
            Core::FITKNode point1(connectPoint[0], connectPoint[1], connectPoint[2]);
            double distance = Core::Distance(*point, point1);
            //添加半无限流体连接
            Acoustics::FITKSEASubSysSEIFConnectedSubSys* semiDataConnect = new Acoustics::FITKSEASubSysSEIFConnectedSubSys();
            semiDataConnect->setSubSysID(subID);
            semiDataConnect->setConnectPos(connectPoint);
            semiDataConnect->setDistance(distance);
            semiData->appendDataObj(semiDataConnect);
        }
        //分组模式
        else if (_ui->radioButton_Group->isChecked())
        {
            //获取分组数据
            Acoustics::FITKAcousticsGroupManager* groupManager = Acoustics::FITKAcousticsGroupManager::GetGroupManagerFromFrame();
            if (!groupManager) return;
            int groupID = _ui->comboBox_Group->currentData().toInt();
            Acoustics::FITKAcousticsGroupData* groupData = groupManager->getDataByID(groupID);
            if (!groupData)
            {
                QMessageBox::warning(this, "", QString(tr("Unable to connect! There is no grouped data.")), QMessageBox::Ok);
                return;
            }
            //获取子系统数据
            int count = groupData->getDataCount();
            for (int i = 0; i < count; ++i)
            {
                Acoustics::FITKAcousticsGroupData::AcousticsGroupData data = groupData->getGroupDataAt(i);
                if (data._objType != Acoustics::FITKAcousticsGroupData::AcousticsGroupDataType::AcousticsSEASubsystem) continue;
                if (data._type == Acoustics::FITKAbstractSEASubSys::SEASemiIInfiniteFluid || data._type == Acoustics::FITKAbstractSEASubSys::SEABeam
                    || data._type == Acoustics::FITKAbstractSEASubSys::SEACavity || data._type == Acoustics::FITKAbstractSEASubSys::SEASSNone)continue;
                Acoustics::FITKAbstractSEASubSysShell* subData = dynamic_cast<Acoustics::FITKAbstractSEASubSysShell*>(subManager->getDataByID(data._objID));
                if (!subData) continue;
                //获取连接点
                double connectPoint[3] = { 0,0,0 };
                calculateConnectPoint(subData, connectPoint);
                Core::FITKNode point1(connectPoint[0], connectPoint[1], connectPoint[2]);
                double distance = Core::Distance(*point, point1);
                //添加半无限流体连接
                Acoustics::FITKSEASubSysSEIFConnectedSubSys* semiDataConnect = new Acoustics::FITKSEASubSysSEIFConnectedSubSys();
                semiDataConnect->setSubSysID(data._objID);
                semiDataConnect->setConnectPos(connectPoint);
                semiDataConnect->setDistance(distance);
                semiData->appendDataObj(semiDataConnect);
            }
        }
        _oper->setArgs("DataID", semiID);
        this->accept();
    }

    void SemiInfiniteFluidConnectDialog::calculateConnectPoint(GraphData::PickedFaceData pickData, double* point)
    {
        //获取数据管理器
        if (!_SEAModel || !_DiscModel) return;
        Acoustics::FITKSEAFaceManager* faceManager = _SEAModel->getSEAFaceManager();
        Acoustics::FITKAcousticsDiscNodeList* nodeList = _DiscModel->getNodes();
        if (nodeList == nullptr || faceManager == nullptr)return;
        //获取拾取的数据
        int faceID = pickData.FaceId;
        int eleIndex = pickData.ElementId;
        //获取拾取的单元
        QList<int> allNodes = {};
        Acoustics::FITKAbstractSEAFace* face = faceManager->getDataByID(faceID);
        if (face != nullptr) {
            Acoustics::FITKAcousticsTriangles* eleS = face->getTriangleMesh();
            if (eleS != nullptr && eleS->getElementCount() > eleIndex) {
                Interface::FITKAbstractElement* ele = eleS->getElementAt(eleIndex);
                if (ele != nullptr) allNodes = ele->getAllNodes();
            }
        }
        if (allNodes.size() == 0)return;
        //获取单元上的点数据
        QList<Core::FITKNode*> points = {};
        for (int nodeID : allNodes) {
            Core::FITKNode* point = nodeList->getNodeByID(nodeID);
            if (point == nullptr)continue;
            double node[3] = { 0,0,0 };
            points.append(point);
        }
        if (points.size() != 3)return;
        //计算连接位置
        point[0] = (points[0]->x() + points[1]->x() + points[2]->x()) / 3;
        point[1] = (points[0]->y() + points[1]->y() + points[2]->y()) / 3;
        point[2] = (points[0]->z() + points[1]->z() + points[2]->z()) / 3;
    }

    void SemiInfiniteFluidConnectDialog::calculateConnectPoint(Acoustics::FITKAbstractSEASubSysShell* subData, double* point)
    {
        if (!subData || !_DiscModel) return;
        Acoustics::FITKAcousticsDiscNodeList* nodeList = _DiscModel->getNodes();
        //获取面数据
        Acoustics::FITKAbstractSEAFace* face = subData->getFaceObj();
        if (nodeList == nullptr || !face) return;
        Acoustics::FITKAcousticsTriangles* eleS = face->getTriangleMesh();
        if (!eleS) return;
        //获取第一个单元
        Interface::FITKAbstractElement* ele = eleS->getElementAt(0);
        if (!ele) return;
        QList<int> allNodes = ele->getAllNodes();
        //获取单元上的点数据
        QList<Core::FITKNode*> points = {};
        for (int nodeID : allNodes) {
            Core::FITKNode* point = nodeList->getNodeByID(nodeID);
            if (point == nullptr)continue;
            double node[3] = { 0,0,0 };
            points.append(point);
        }
        if (points.size() != 3)return;
        //计算连接位置
        point[0] = (points[0]->x() + points[1]->x() + points[2]->x()) / 3;
        point[1] = (points[0]->y() + points[1]->y() + points[2]->y()) / 3;
        point[2] = (points[0]->z() + points[1]->z() + points[2]->z()) / 3;
    }
}
